using System;
using System.Collections;
using System.Collections.Generic;

namespace ICSharpCode.TextEditor.Util
{
	public class WeakCollection<T> : IEnumerable<T>, IEnumerable where T : class
	{
		private readonly List<WeakReference> innerList = new List<WeakReference>();

		private bool hasEnumerator;

		public void Add(T item)
		{
			if (item == null)
			{
				throw new ArgumentNullException("item");
			}
			this.CheckNoEnumerator();
			if (this.innerList.Count == this.innerList.Capacity || this.innerList.Count % 32 == 31)
			{
				this.innerList.RemoveAll((WeakReference r) => !r.IsAlive);
			}
			this.innerList.Add(new WeakReference(item));
		}

		public void Clear()
		{
			this.innerList.Clear();
			this.CheckNoEnumerator();
		}

		public bool Contains(T item)
		{
			if (item == null)
			{
				throw new ArgumentNullException("item");
			}
			this.CheckNoEnumerator();
			foreach (T item2 in this)
			{
				if (item.Equals(item2))
				{
					return true;
				}
			}
			return false;
		}

		public bool Remove(T item)
		{
			if (item == null)
			{
				throw new ArgumentNullException("item");
			}
			this.CheckNoEnumerator();
			int num = 0;
			while (num < this.innerList.Count)
			{
				T val = (T)this.innerList[num].Target;
				if (val == null)
				{
					this.RemoveAt(num);
					continue;
				}
				if (val == item)
				{
					this.RemoveAt(num);
					return true;
				}
				num++;
			}
			return false;
		}

		private void RemoveAt(int i)
		{
			int index = this.innerList.Count - 1;
			this.innerList[i] = this.innerList[index];
			this.innerList.RemoveAt(index);
		}

		private void CheckNoEnumerator()
		{
			if (this.hasEnumerator)
			{
				throw new InvalidOperationException("The WeakCollection is already being enumerated, it cannot be modified at the same time. Ensure you dispose the first enumerator before modifying the WeakCollection.");
			}
		}

		public IEnumerator<T> GetEnumerator()
		{
			if (this.hasEnumerator)
			{
				throw new InvalidOperationException("The WeakCollection is already being enumerated, it cannot be enumerated twice at the same time. Ensure you dispose the first enumerator before using another enumerator.");
			}
			try
			{
				this.hasEnumerator = true;
				int i = 0;
				while (i < this.innerList.Count)
				{
					T element = (T)this.innerList[i].Target;
					if (element == null)
					{
						this.RemoveAt(i);
						continue;
					}
					yield return element;
					i++;
				}
			}
			finally
			{
				this.hasEnumerator = false;
			}
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}
	}
}
